package vip.xiaomaoxiaoke.msg.interceptor;


import vip.xiaomaoxiaoke.msg.annotate.LocalMessage;
import vip.xiaomaoxiaoke.msg.message.impl.NativeMethodMessage;
import vip.xiaomaoxiaoke.msg.service.ReliableMethodExecuteService;
import vip.xiaomaoxiaoke.msg.util.SerializeUtil;
import lombok.SneakyThrows;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 本地消息表注解拦截器
 * */
@Slf4j
public class LocalMessageAnnotationInterceptor implements MethodInterceptor, BeanPostProcessor {


    ReliableMethodExecuteService reliableMessageSendService ;

    public static Map<String,Mk> map = new HashMap<>();


    public LocalMessageAnnotationInterceptor(ReliableMethodExecuteService reliableMessageSendService) {
        this.reliableMessageSendService = reliableMessageSendService;
    }

    @Value
    public class  Mk {
        private Object bean;

        private Method method;
    }
    private final Map<Method, InvokeCacheItem> invokeCache = new ConcurrentHashMap<>();

    @SneakyThrows
    @Override
    public Object postProcessAfterInitialization(Object proxy, String beanName) throws BeansException {
        // 1. 获取 @AsyncBasedRocketMQ 注解方法
        Class targetCls = AopUtils.getTargetClass(proxy);
        List<Method> methodsListWithAnnotation = MethodUtils.getMethodsListWithAnnotation(targetCls, LocalMessage.class);

        // 2. 为每个 @AsyncBasedRocketMQ 注解方法 注册 NormalAsyncConsumerContainer
        for(Method method : methodsListWithAnnotation){
            if (method.isBridge()){
                log.warn("method {} is bridge, break!", method);
                continue;
            }
            map.put(generateMethodKey(method),new Mk(AopProxyUtils.getSingletonTarget(proxy),method));
            LocalMessage annotation = method.getAnnotation(LocalMessage.class);

        }

        return proxy;
    }



    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        Method method = methodInvocation.getMethod();

        InvokeCacheItem invokeCacheItem = this.invokeCache.computeIfAbsent(method, this::parseMethod);
        // 获取方法参数
        Object[] arguments = methodInvocation.getArguments();

        // 创建 SpEL 上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        String[] parameterNames = getParameterNames(method); // 获取方法参数名
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], arguments[i]);
        }

        // 使用 SpEL 表达式解析 msgKey
        ExpressionParser parser = new SpelExpressionParser();
        String msgKey = parser.parseExpression(invokeCacheItem.msgIdExpression).getValue(context, String.class);

        String serialize = serialize(methodInvocation.getArguments());
        NativeMethodMessage nativeMethodMessageMessage = (NativeMethodMessage) new NativeMethodMessage()
                .setParamValueList(serialize)
                .setMethodKey(generateMethodKey(method))
                .setMsgId(msgKey)
                .setOrderly(invokeCacheItem.isOrderly())
                .setMaxRetries(invokeCacheItem.maxRetries)
                .setShardingKey(invokeCacheItem.shardingKey)
                .setTimeTnterval(invokeCacheItem.timeTnterval);

        reliableMessageSendService.saveAndSend(nativeMethodMessageMessage);

        return null;
    }
    // 获取方法参数名的工具方法
    private String[] getParameterNames(Method method) {
        // 这里可以使用 Spring 的 ParameterNameDiscoverer 或其他工具
        return Arrays.stream(method.getParameters())
                .map(param -> param.getName()) // 如果编译时启用了 -parameters，则可以直接获取参数名
                .toArray(String[]::new);
    }
    /**
     * 序列化操作
     * @param arguments
     * @return
     */
    protected String serialize(Object[] arguments) {
        Map<String, String> result = new ConcurrentHashMap<>();
        for (int i = 0; i < arguments.length; i++){
            result.put(String.valueOf(i), SerializeUtil.serialize(arguments[i]));
        }
        return SerializeUtil.serialize(result);
    }


    private Object[]  deserialize(String str,Method method) {
        Map deserialize = SerializeUtil.deserialize(str, Map.class);
        Object[] params = new Object[method.getParameterCount()];

        // 根据类型对每个参数进行反序列化
        for (int i = 0; i < method.getParameterCount(); i++) {
            String o = (String) deserialize.get(String.valueOf(i));
            if (o == null) {
                params[i] = null;
            } else {
                params[i] = SerializeUtil.deserialize(o, method.getParameterTypes()[i]);
            }
        }
        return params;
    }

    private String generateMethodKey(Method method) {
        // 获取目标类的全限定类名
        String className = method.getDeclaringClass().getName();

        // 获取方法名
        String methodName = method.getName();

        // 构建方法签名
        StringBuilder methodSignatureBuilder = new StringBuilder(className)
                .append(".").append(methodName).append("(");

        // 遍历方法参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) {
            if (i > 0) methodSignatureBuilder.append(", ");
            methodSignatureBuilder.append(parameterTypes[i].getName());
        }
        methodSignatureBuilder.append(")");



        return methodSignatureBuilder.toString();
    }

    private InvokeCacheItem  parseMethod(Method method){
        LocalMessage localMessage = method.getAnnotation(LocalMessage.class);



        return new InvokeCacheItem(
                localMessage.msgIdExpression(),
                localMessage.orderly(),
                localMessage.shardingKey(),
                localMessage.timeTnterval(),
                localMessage.maxRetries());
    }

    /**
     * 换成注解数据，可能需要对换成做一些预处理
     * */
    @Value
    class InvokeCacheItem{
        private final String msgIdExpression;
        private final boolean orderly;
        private final String shardingKey;
        private final int timeTnterval;
        private final int maxRetries;

    }



}
